/*
 *  Netzpult - Your desk on the web
 *  Copyright (C) 2011  Ulrich Hilger, http://uhilger.de
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/
 */

package de.uhilger.netzpult.server;

import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import de.uhilger.netzpult.server.db.DataStorage;
import de.uhilger.netzpult.server.db.DataStorageImpl;
import de.uhilger.netzpult.shared.Document;
import de.uhilger.netzpult.shared.Folder;

/**
 * 
 * @author Copyright (c) Ulrich Hilger, http://uhilger.de
 * @author Published under the terms and conditions of
 * the <a href="http://www.gnu.org/licenses/" target="_blank">GNU General Public License</a>
 */
public abstract class AbstractWebfilesServlet extends RemoteServiceServlet {

	private static final long serialVersionUID = 6024943874108318109L;

	public static final String DB_TYPE = "dbtype";
	public static final String MODE = "mode";
	public static final String DB_URL = "dburl";
	public static final String LOGLEVEL = "loglevel";
	public static final String DEFAULT_OWNER = "default_owner";
	public static final String DEFAULT_DOCUMENT = "default_document";
	
	public static final String DEVELOPMENT_MODE = "development";
	public static final String PRODUCTION_MODE = "production";
	
	public static final String ANONYMOUS_OWNER = "anonymous";

	public static final String DB_TYPE_MYSQL = "mysql";
	public static final String DB_TYPE_DERBY = "derby";
	
	protected DataStorage ds;
	protected String userName;
	protected String mode;
	protected String dbtype;
	//protected String editorLoadDelay;
	protected String defaultOwner = ANONYMOUS_OWNER;
	protected int depth;
	protected String defaultDocumentId;

	@Override
	public void init(ServletConfig config) throws ServletException {
		
		ServletContext context = config.getServletContext();

		mode = context.getInitParameter(MODE);
		dbtype = context.getInitParameter(DB_TYPE);
		String dburl = context.getInitParameter(DB_URL);
		//editorLoadDelay = context.getInitParameter(PublicService.EDITOR_LOAD_DELAY);
		defaultOwner = context.getInitParameter(DEFAULT_OWNER);
		defaultDocumentId = context.getInitParameter(DEFAULT_DOCUMENT);
		
		Level loglevel = Level.FINEST;
		if(config != null) {
			String logLevelStr = context.getInitParameter(LOGLEVEL);
			System.out.println("AbstractWebfilesServlet loglevel=" + logLevelStr);
			if(logLevelStr != null) {
				loglevel = Level.parse(logLevelStr.toUpperCase());
			}
		}

		Object o = context.getAttribute(DataStorage.NAME);
		if (o == null) {
			System.out.println(new Date() + " AbstractWebfilesServlet.init creating DatabaseAdapter");
			ds = new DataStorageImpl(mode, dbtype, dburl);
			context.setAttribute(DataStorage.NAME, ds);
		} else {
			ds = (DataStorage) o;
		}
		Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
		Handler[] handlers = globalLogger.getHandlers();
		if(handlers.length == 0) {
			Handler handler = new ConsoleHandler();
			handler.setLevel(loglevel);
			globalLogger.addHandler(handler);
		} else {
			for(int i = 0; i < handlers.length; i++) {
				handlers[i].setLevel(loglevel);
			}
		}
		globalLogger.setLevel(loglevel);
		globalLogger.info("loglevel=" + globalLogger.getLevel().toString());
		super.init(config);
	}
	
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest(".");
		userName = getUserName(request);
		//if(request.getContentType().equals("text/x-gwt-rpc")) {
			super.service(request, response);
		//}
	}
	
	public String getParameter(String parameterName) throws Exception {
		String value = null;
		if(parameterName.equals(MODE)) {
			value = mode;
		} else if(parameterName.equals(DB_TYPE)) {
			value = dbtype;
		} /*else if(parameterName.equals(PublicService.EDITOR_LOAD_DELAY)) {
			value = editorLoadDelay;
		} */ else {
			throw new Exception(parameterName + " is not a valid parameter name, use either '" + mode + "' or '" + DB_TYPE + "'");
		}
		return value;
	}
	
	protected String getUserName(HttpServletRequest req) {
		String userName = null;
		Principal p = req.getUserPrincipal();
		if(p != null) {
			userName = p.getName();
		}
		if(userName == null) {
			userName = ANONYMOUS_OWNER;
		}
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest(userName);
		return userName;
	}

	protected Document getDocument(String pathInfo) throws Exception {
		Document document = null;
		String[] pathElements = pathInfo.split("/");
		String owner = pathElements[1];
		depth = pathElements.length;
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest("depth=" + depth);
		if(depth < 4) {
			Folder folder = Folder.getPublicFolder();
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest(
					"looking for documents for owner " + owner + 
					" folder " + folder.getId() + " " + folder.getName() +
					" document name " + pathElements[pathElements.length - 1]);
			document = getDocument(pathElements[pathElements.length - 1], owner, folder);
		} else {
			List<Folder> path = new ArrayList<Folder>();
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest("owner=" + owner);
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest("pathElements[2]=" + pathElements[2]);		
			List<Folder> folders = ds.getFolder(Folder.PUBLIC_FOLDER_ID,
					pathElements[2]);
			if (folders != null && folders.size() > 0) {
				Folder folder = folders.get(0);
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest("found folder " + folder.getId() + " " + folder.getName());
				path.add(folder);
				int i = 3;
				while (i < pathElements.length - 1) {
					Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest(
							"parent folder " + folder.getId() + " pathElements[" + i + "]=" + pathElements[i]);		
					folders = ds.getFolder(folder.getId(), pathElements[i]);
					if (folders != null && folders.size() > 0) {
						folder = folders.get(0);
						Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest("found folder " + folder.getId() + " " + folder.getName());
						path.add(folder);
					}
					i++;
				}
				Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).finest(
						"looking for documents for owner " + owner + 
						" folder " + folder.getId() + " " + folder.getName() +
						" document name " + pathElements[pathElements.length - 1]);
				document = getDocument(pathElements[pathElements.length - 1], owner, folder);
			}
		}
		return document;
	}
	
	private Document getDocument(String docName, String owner, Folder folder) throws Exception {
		Document document = null;
		List<Document> documents = ds.getDocuments(owner, folder, DataStorage.WITH_DRAFT);
		Iterator<Document> docIter = documents.iterator();
		while (docIter.hasNext() && document == null) {
			Document testDoc = docIter.next();
			DocumentServer.logText("testing document " + testDoc.getId() + " " + testDoc.getTitle());
			if (testDoc.getTitle().equals(docName)) {
				document = testDoc;
			}
		}
		return document;
	}
		
}
